package gcode

import (
	"fmt"
	"path/filepath"
	"strings"
)

// generateModels 生成模型代码
func (g *generatorService) generateModels(files map[string]string) error {
	for tableName, tableStruct := range g.tables {
		tableConfig, ok := g.tableConfigs[tableName]
		if !ok {
			fmt.Printf("错误: 找不到表配置信息: %s\n", tableName)
			return fmt.Errorf("找不到表配置信息: %s", tableName)
		}

		// 准备模板数据
		type FieldInfo struct {
			Name         string // 字段名称（Go格式）
			ColumnName   string // 数据库列名
			Type         string // Go类型
			Tag          string // 字段标签
			Comment      string // 注释
			IsPrimaryKey bool   // 是否为主键
		}

		type ModelData struct {
			PackageName  string
			ModelName    string
			TableName    string
			Fields       []FieldInfo
			PrimaryKey   string
			Comment      string
			UseCamelCase bool
		}

		fmt.Printf("开始处理表模型: %s\n", tableName)

		// 处理字段信息
		var fields []FieldInfo
		var primaryKey string

		// 检查是否有主键
		hasPrimaryKey := len(tableStruct.PrimaryKeys) > 0
		if !hasPrimaryKey {
			fmt.Printf("警告: 表 %s 没有主键\n", tableName)
		}

		for _, column := range tableStruct.Columns {
			// 确定Go类型
			goType := sqlTypeToGoType(column.Type)

			// 确定字段名称
			fieldName := column.Name
			if tableConfig.UseCamelCase {
				fieldName = toCamelCase(column.Name)
			}

			// 判断是否为主键
			isPrimaryKey := false
			for _, pk := range tableStruct.PrimaryKeys {
				if pk == column.Name {
					isPrimaryKey = true
					primaryKey = fieldName
					break
				}
			}

			// 生成标签
			tag := fmt.Sprintf(`json:"%s" form:"%s" gorm:"column:%s`,
				toSnakeCase(fieldName), toSnakeCase(fieldName), column.Name)

			if isPrimaryKey {
				tag += ";primaryKey"
				if column.Extra == "auto_increment" {
					tag += ";autoIncrement"
				}
			}

			if column.Nullable == "NO" && !isPrimaryKey {
				tag += ";not null"
			}

			if column.Comment != "" {
				tag += fmt.Sprintf(`;comment:%s`, column.Comment)
			}

			tag += `"`

			// 创建字段信息
			field := FieldInfo{
				Name:         fieldName,
				ColumnName:   column.Name,
				Type:         goType,
				Tag:          tag,
				Comment:      column.Comment,
				IsPrimaryKey: isPrimaryKey,
			}

			fields = append(fields, field)
		}

		// 如果没有主键，则使用第一个字段作为默认主键（仅用于生成代码，不实际设置主键）
		if primaryKey == "" && len(fields) > 0 {
			primaryKey = fields[0].Name
			fmt.Printf("没有找到主键，使用第一个字段 %s 替代\n", primaryKey)
		}

		// 准备模板数据
		data := ModelData{
			PackageName:  g.config.PackageName,
			ModelName:    tableConfig.ModelName,
			TableName:    tableConfig.TableName,
			Fields:       fields,
			PrimaryKey:   primaryKey,
			Comment:      tableStruct.Comment,
			UseCamelCase: tableConfig.UseCamelCase,
		}

		// 渲染模型模板
		modelContent, err := g.renderTemplate(modelTemplate, data)
		if err != nil {
			fmt.Printf("生成模型代码失败: %v\n", err)
			return fmt.Errorf("生成模型代码失败: %w", err)
		}

		// 保存生成的模型文件
		modelFilePath := filepath.Join("internal", "model", strings.ToLower(tableConfig.TableName)+"_model.go")
		files[modelFilePath] = modelContent
		fmt.Printf("生成模型文件: %s\n", modelFilePath)
	}

	return nil
}

// generateRepositories 生成仓库层代码
func (g *generatorService) generateRepositories(files map[string]string) error {
	for tableName, tableStruct := range g.tables {
		tableConfig, ok := g.tableConfigs[tableName]
		if !ok {
			fmt.Printf("错误: 找不到表配置信息: %s\n", tableName)
			return fmt.Errorf("找不到表配置信息: %s", tableName)
		}

		fmt.Printf("开始生成仓库代码: %s\n", tableName)

		// 准备模板数据
		type RepoData struct {
			PackageName  string
			ModelName    string
			TableName    string
			PrimaryKey   string
			Comment      string
			UseCamelCase bool
		}

		// 获取主键信息
		var primaryKey string

		for _, column := range tableStruct.Columns {
			for _, pk := range tableStruct.PrimaryKeys {
				if pk == column.Name {
					if tableConfig.UseCamelCase {
						primaryKey = toCamelCase(column.Name)
					} else {
						primaryKey = column.Name
					}
					break
				}
			}
		}

		// 如果没有找到主键，使用第一个字段作为默认主键（仅用于生成代码）
		if primaryKey == "" && len(tableStruct.Columns) > 0 {
			if tableConfig.UseCamelCase {
				primaryKey = toCamelCase(tableStruct.Columns[0].Name)
			} else {
				primaryKey = tableStruct.Columns[0].Name
			}
			fmt.Printf("仓库层: 未找到主键，使用第一个字段 %s 作为主键\n", primaryKey)
		} else if primaryKey == "" {
			// 如果连一个字段都没有（极少情况）, 使用默认值 "Id"
			primaryKey = "Id"
			fmt.Printf("警告: 表 %s 没有字段，使用默认主键 Id\n", tableName)
		}

		// 准备模板数据
		data := RepoData{
			PackageName:  g.config.PackageName,
			ModelName:    tableConfig.ModelName,
			TableName:    tableConfig.TableName,
			PrimaryKey:   primaryKey,
			Comment:      tableStruct.Comment,
			UseCamelCase: tableConfig.UseCamelCase,
		}

		// 渲染仓库模板
		repoContent, err := g.renderTemplate(repositoryTemplate, data)
		if err != nil {
			fmt.Printf("生成仓库代码失败: %v\n", err)
			return fmt.Errorf("生成仓库代码失败: %w", err)
		}

		// 保存生成的仓库文件
		repoFilePath := filepath.Join("internal", "repo", strings.ToLower(tableConfig.TableName)+"_repo.go")
		files[repoFilePath] = repoContent
		fmt.Printf("生成仓库文件: %s\n", repoFilePath)
	}

	return nil
}

// generateServices 生成服务层代码
func (g *generatorService) generateServices(files map[string]string) error {
	for tableName, tableStruct := range g.tables {
		tableConfig, ok := g.tableConfigs[tableName]
		if !ok {
			fmt.Printf("错误: 找不到表配置信息: %s\n", tableName)
			return fmt.Errorf("找不到表配置信息: %s", tableName)
		}

		fmt.Printf("开始生成服务层代码: %s\n", tableName)

		// 准备模板数据
		type ServiceData struct {
			PackageName string
			ModelName   string
			TableName   string
			PrimaryKey  string
			Comment     string
		}

		// 获取主键信息
		var primaryKey string

		for _, column := range tableStruct.Columns {
			for _, pk := range tableStruct.PrimaryKeys {
				if pk == column.Name {
					if tableConfig.UseCamelCase {
						primaryKey = toCamelCase(column.Name)
					} else {
						primaryKey = column.Name
					}
					break
				}
			}
		}

		// 如果没有找到主键，使用第一个字段作为默认主键（仅用于生成代码）
		if primaryKey == "" && len(tableStruct.Columns) > 0 {
			if tableConfig.UseCamelCase {
				primaryKey = toCamelCase(tableStruct.Columns[0].Name)
			} else {
				primaryKey = tableStruct.Columns[0].Name
			}
			fmt.Printf("服务层: 未找到主键，使用第一个字段 %s 作为主键\n", primaryKey)
		} else if primaryKey == "" {
			// 如果连一个字段都没有（极少情况）, 使用默认值 "Id"
			primaryKey = "Id"
			fmt.Printf("警告: 表 %s 没有字段，使用默认主键 Id\n", tableName)
		}

		// 准备模板数据
		data := ServiceData{
			PackageName: g.config.PackageName,
			ModelName:   tableConfig.ModelName,
			TableName:   tableConfig.TableName,
			PrimaryKey:  primaryKey,
			Comment:     tableStruct.Comment,
		}

		// 渲染服务模板
		serviceContent, err := g.renderTemplate(serviceTemplate, data)
		if err != nil {
			fmt.Printf("生成服务代码失败: %v\n", err)
			return fmt.Errorf("生成服务代码失败: %w", err)
		}

		// 保存生成的服务文件
		serviceFilePath := filepath.Join("internal", "service", strings.ToLower(tableConfig.TableName)+"_service.go")
		files[serviceFilePath] = serviceContent
		fmt.Printf("生成服务文件: %s\n", serviceFilePath)
	}

	return nil
}

// generateControllers 生成控制器代码
func (g *generatorService) generateControllers(files map[string]string) error {
	for tableName, tableStruct := range g.tables {
		tableConfig, ok := g.tableConfigs[tableName]
		if !ok {
			fmt.Printf("错误: 找不到表配置信息: %s\n", tableName)
			return fmt.Errorf("找不到表配置信息: %s", tableName)
		}

		fmt.Printf("开始生成控制器代码: %s\n", tableName)

		// 准备模板数据
		type ControllerData struct {
			PackageName    string
			ModelName      string
			TableName      string
			LowerModelName string
			PrimaryKey     string
			Comment        string
			ModuleName     string
		}

		// 获取主键信息
		var primaryKey string

		for _, column := range tableStruct.Columns {
			for _, pk := range tableStruct.PrimaryKeys {
				if pk == column.Name {
					if tableConfig.UseCamelCase {
						primaryKey = toCamelCase(column.Name)
					} else {
						primaryKey = column.Name
					}
					break
				}
			}
		}

		// 如果没有找到主键，使用第一个字段作为默认主键（仅用于生成代码）
		if primaryKey == "" && len(tableStruct.Columns) > 0 {
			if tableConfig.UseCamelCase {
				primaryKey = toCamelCase(tableStruct.Columns[0].Name)
			} else {
				primaryKey = tableStruct.Columns[0].Name
			}
			fmt.Printf("控制器层: 未找到主键，使用第一个字段 %s 作为主键\n", primaryKey)
		} else if primaryKey == "" {
			// 如果连一个字段都没有（极少情况），使用默认值 "Id"
			primaryKey = "Id"
			fmt.Printf("警告: 表 %s 没有字段，使用默认主键 Id\n", tableName)
		}

		// 准备模板数据
		data := ControllerData{
			PackageName:    g.config.PackageName,
			ModelName:      tableConfig.ModelName,
			TableName:      tableConfig.TableName,
			LowerModelName: strings.ToLower(tableConfig.TableName),
			PrimaryKey:     primaryKey,
			Comment:        tableStruct.Comment,
			ModuleName:     g.config.ModuleName,
		}

		// 渲染控制器模板
		controllerContent, err := g.renderTemplate(controllerTemplate, data)
		if err != nil {
			fmt.Printf("生成控制器代码失败: %v\n", err)
			return fmt.Errorf("生成控制器代码失败: %w", err)
		}

		// 保存生成的控制器文件
		controllerDir := filepath.Join("internal", "handler", g.config.ModuleName)
		controllerFilePath := filepath.Join(controllerDir, strings.ToLower(tableConfig.TableName)+"_handler.go")
		files[controllerFilePath] = controllerContent
		fmt.Printf("生成控制器文件: %s\n", controllerFilePath)
	}

	return nil
}

// generateRouters 生成路由代码
func (g *generatorService) generateRouters(files map[string]string) error {
	// 收集所有模型名称
	var models []string

	for tableName, tableStruct := range g.tables {
		tableConfig, ok := g.tableConfigs[tableName]
		if !ok {
			fmt.Printf("错误: 找不到表配置信息: %s\n", tableName)
			return fmt.Errorf("找不到表配置信息: %s", tableName)
		}

		if tableStruct == nil {
			fmt.Printf("警告: 表结构为空: %s\n", tableName)
			continue
		}

		models = append(models, tableConfig.ModelName)
	}

	fmt.Printf("开始生成路由文件，包含模型: %v\n", models)

	if len(models) == 0 {
		fmt.Printf("没有有效的模型可以生成路由\n")
		return nil
	}

	// 确保模块名不为空
	moduleName := g.config.ModuleName
	if moduleName == "" {
		moduleName = "default"
		fmt.Printf("模块名为空，使用默认值: %s\n", moduleName)
	}

	// 准备模板数据
	type RouterData struct {
		PackageName string
		ModuleName  string
		Models      []string
	}

	data := RouterData{
		PackageName: g.config.PackageName,
		ModuleName:  moduleName,
		Models:      models,
	}

	// 渲染路由模板
	routerContent, err := g.renderTemplate(routerTemplate, data)
	if err != nil {
		fmt.Printf("生成路由代码失败: %v\n", err)
		return fmt.Errorf("生成路由代码失败: %w", err)
	}

	// 保存生成的路由文件
	routerFilePath := filepath.Join("internal", "router", strings.ToLower(moduleName)+"_router.go")
	files[routerFilePath] = routerContent
	fmt.Printf("生成路由文件: %s\n", routerFilePath)

	// 确保控制器目录存在
	controllerDir := filepath.Join("internal", "handler", moduleName)
	files[filepath.Join(controllerDir, ".gitkeep")] = ""
	fmt.Printf("创建控制器目录占位文件: %s\n", filepath.Join(controllerDir, ".gitkeep"))

	return nil
}

// generateRequestDtos 生成请求DTO
func (g *generatorService) generateRequestDtos(files map[string]string) error {
	for tableName, tableStruct := range g.tables {
		tableConfig, ok := g.tableConfigs[tableName]
		if !ok {
			fmt.Printf("错误: 找不到表配置信息: %s\n", tableName)
			return fmt.Errorf("找不到表配置信息: %s", tableName)
		}

		// 准备模板数据
		type FieldInfo struct {
			Name         string // 字段名称（Go格式）
			ColumnName   string // 数据库列名（JSON标签名）
			Type         string // Go类型
			Comment      string // 注释
			IsPrimaryKey bool   // 是否为主键
			ValidateTag  string // 验证标签
		}

		type RequestDtoData struct {
			PackageName      string
			ModelName        string
			Comment          string
			Fields           []FieldInfo
			PrimaryKey       string
			PrimaryKeyType   string
			PrimaryKeyColumn string
		}

		fmt.Printf("开始生成请求DTO: %s\n", tableName)

		// 处理字段信息
		var fields []FieldInfo
		var primaryKey string
		var primaryKeyType string
		var primaryKeyColumn string

		// 检查是否有主键
		for _, column := range tableStruct.Columns {
			// 确定Go类型
			goType := sqlTypeToGoType(column.Type)

			// 确定字段名称
			fieldName := column.Name
			if tableConfig.UseCamelCase {
				fieldName = toCamelCase(column.Name)
			}

			// 判断是否为主键并准备验证标签
			isPrimaryKey := false
			validateTag := ""

			for _, pk := range tableStruct.PrimaryKeys {
				if pk == column.Name {
					isPrimaryKey = true
					primaryKey = fieldName
					primaryKeyType = goType
					primaryKeyColumn = column.Name
					validateTag = "required"
					break
				}
			}

			// 对非空字段添加required验证
			if column.Nullable == "NO" && !isPrimaryKey &&
				column.Name != "create_time" && column.Name != "update_time" && column.Name != "delete_time" {
				if validateTag != "" {
					validateTag += ","
				}
				validateTag += "required"
			}

			// 根据字段类型添加适当的验证
			if strings.Contains(strings.ToLower(goType), "string") {
				// 对字符串类型可以加入长度验证
				if validateTag != "" {
					validateTag += ","
				}
				validateTag += "max=255"
			} else if strings.Contains(strings.ToLower(goType), "int") && !isPrimaryKey {
				// 对数字类型加入范围验证
				if validateTag != "" {
					validateTag += ","
				}
				validateTag += "gte=0"
			}

			// 创建字段信息
			field := FieldInfo{
				Name:         fieldName,
				ColumnName:   toSnakeCase(fieldName),
				Type:         goType,
				Comment:      column.Comment,
				IsPrimaryKey: isPrimaryKey,
				ValidateTag:  validateTag,
			}

			fields = append(fields, field)
		}

		// 准备模板数据
		data := RequestDtoData{
			PackageName:      g.config.PackageName,
			ModelName:        tableConfig.ModelName,
			Comment:          tableStruct.Comment,
			Fields:           fields,
			PrimaryKey:       primaryKey,
			PrimaryKeyType:   primaryKeyType,
			PrimaryKeyColumn: primaryKeyColumn,
		}

		// 渲染请求DTO模板
		requestDtoContent, err := g.renderTemplate(requestDtoTemplate, data)
		if err != nil {
			fmt.Printf("生成请求DTO代码失败: %v\n", err)
			return fmt.Errorf("生成请求DTO代码失败: %w", err)
		}

		// 保存生成的请求DTO文件
		requestDtoFilePath := filepath.Join("internal", "dto", "request", strings.ToLower(tableConfig.TableName)+"_request.go")
		files[requestDtoFilePath] = requestDtoContent
		fmt.Printf("生成请求DTO文件: %s\n", requestDtoFilePath)
	}

	return nil
}

// generateResponseDtos 生成响应DTO
func (g *generatorService) generateResponseDtos(files map[string]string) error {
	for tableName, tableStruct := range g.tables {
		tableConfig, ok := g.tableConfigs[tableName]
		if !ok {
			fmt.Printf("错误: 找不到表配置信息: %s\n", tableName)
			return fmt.Errorf("找不到表配置信息: %s", tableName)
		}

		// 准备模板数据
		type FieldInfo struct {
			Name         string // 字段名称（Go格式）
			ColumnName   string // 数据库列名（JSON标签名）
			Type         string // Go类型
			Comment      string // 注释
			IsPrimaryKey bool   // 是否为主键
		}

		type ResponseDtoData struct {
			PackageName string
			ModelName   string
			Comment     string
			Fields      []FieldInfo
		}

		fmt.Printf("开始生成响应DTO: %s\n", tableName)

		// 处理字段信息
		var fields []FieldInfo

		for _, column := range tableStruct.Columns {
			// 确定Go类型
			goType := sqlTypeToGoType(column.Type)

			// 确定字段名称
			fieldName := column.Name
			if tableConfig.UseCamelCase {
				fieldName = toCamelCase(column.Name)
			}

			// 判断是否为主键
			isPrimaryKey := false
			for _, pk := range tableStruct.PrimaryKeys {
				if pk == column.Name {
					isPrimaryKey = true
					break
				}
			}

			// 创建字段信息
			field := FieldInfo{
				Name:         fieldName,
				ColumnName:   toSnakeCase(fieldName),
				Type:         goType,
				Comment:      column.Comment,
				IsPrimaryKey: isPrimaryKey,
			}

			fields = append(fields, field)
		}

		// 准备模板数据
		data := ResponseDtoData{
			PackageName: g.config.PackageName,
			ModelName:   tableConfig.ModelName,
			Comment:     tableStruct.Comment,
			Fields:      fields,
		}

		// 渲染响应DTO模板
		responseDtoContent, err := g.renderTemplate(responseDtoTemplate, data)
		if err != nil {
			fmt.Printf("生成响应DTO代码失败: %v\n", err)
			return fmt.Errorf("生成响应DTO代码失败: %w", err)
		}

		// 保存生成的响应DTO文件
		responseDtoFilePath := filepath.Join("internal", "dto", "response", strings.ToLower(tableConfig.TableName)+"_response.go")
		files[responseDtoFilePath] = responseDtoContent
		fmt.Printf("生成响应DTO文件: %s\n", responseDtoFilePath)
	}

	return nil
}
